package com.madixin.chat.exception;

import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public enum ErrorCode {
    /**
     * 通用错误码.
     */
    ILLEGAL_PARAM(Level.SERVER, Module.COMMON, "00", "illegal parameter"),
    ILLEGAL_STATE(Level.SERVER, Module.COMMON, "01", "illegal state"),
    UNSUPPORTED_OPERATION(Level.SERVER, Module.COMMON, "02", "unsupported operation"),
    ILLEGAL_PERMISSION(Level.SERVER, Module.COMMON, "03", "illegal permission"),
    ILLEGAL_CREDENTIALS(Level.SERVER, Module.COMMON, "04", "bad credentials"),
    ILLEGAL_AUTHENTICATE(Level.SERVER, Module.COMMON, "05", "illegal authenticate"),
    FAIL_LOGOUT(Level.SERVER, Module.COMMON, "06", "fail to logout"),

    /**
     * 对话操作异常.
     */
    FAIL_CREATE_SESSION(Level.SERVER, Module.SESSION, "00", "Fail to create session"),
    FAIL_GET_SESSION(Level.SERVER, Module.SESSION, "01", "Fail to get session by id"),
    FAIL_DELETE_SESSION(Level.SERVER, Module.SESSION, "02", "Fail to delete session by id"),
    FAIL_UPDATE_SESSION(Level.SERVER, Module.SESSION, "03", "Fail to update session by id"),
    FAIL_GET_USER_SESSIONS(Level.SERVER, Module.SESSION, "04", "Fail to get user sessions"),
    FAIL_GET_SESSION_MESSAGE(Level.SERVER, Module.SESSION, "05", "Fail to get message of sessions"),
    FAIL_INSERT_SESSION_MESSAGE(Level.SERVER, Module.SESSION, "06", "Fail to insert message of sessions"),
    /**
     * 未知错误.
     */
    UNKNOWN(Level.SYSTEM, Module.UNKNOWN, "00", "unknown error");

    private final String level;
    private final String module;
    private final String code;
    private final String description;

    ErrorCode(String level, String module, String code, String description) {
        this.level = level;
        this.module = module;
        this.code = code;
        this.description = description;
    }

    public String getLevel() {
        return level;
    }

    public String getModule() {
        return module;
    }

    public String getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return String.format(Locale.ENGLISH, "E%s%s%s", this.level, this.module, this.code);
    }

    public String toDetailString() {
        return String.format(Locale.ENGLISH, "%-20s %s   %s", Module.getModuleName(this.getModule()), this.toString(), this.description);
    }

    public static String dumpErrorCodes() {
        return Stream.of(values()).map(ErrorCode::toString).collect(Collectors.joining("\n"));
    }

    public static String dumpDetailErrorCodes() {
        return Stream.of(values()).map(ErrorCode::toDetailString).collect(Collectors.joining("\n"));
    }


    /**
     * 错误级别定义.
     */
    public static class Level {
        /**
         * 系统级错误， 比如IO请求失败，服务请求拒绝，多为不可预测的错误.
         */
        static final String SYSTEM = "1";
        /**
         * 服务级错误，多为业务逻辑不满足要求，比如工程不存在，没有权限等等.
         */
        static final String SERVER = "2";
    }

    /**
     * 错误模块定义.
     */
    @SuppressWarnings("serial")
    public static class Module {
        public static final String USER = "00";
        public static final String SESSION = "01";
        public static final String DEVICE = "02";
        public static final String SCHEDULE = "03";
        public static final String SCENCE = "04";
        public static final String DATABASE = "05";
        public static final String IOT_DATABASE = "06";
        public static final String COMMON = "10";

        public static final String UNKNOWN = "99";

        public static final Map<String, String> MODULE_NAMES = Collections.unmodifiableMap(new HashMap<String, String>() {{
            put(USER, "user");
            put(SESSION, "tenant");
            put(DEVICE, "device");
            put(SCHEDULE, "schedule");
            put(SCENCE, "scence");
            put(IOT_DATABASE, "iot_database");
            put(DATABASE, "database");
            put(COMMON, "common");
            put(UNKNOWN, "unknown");
        }});

        public static String getModuleName(String moduleCode) {
            return MODULE_NAMES.getOrDefault(moduleCode, "unknown");
        }
    }
}
